/**
 * 
 */
package pl.net.beercrm.stats;

import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import pl.net.beercrm.model.Analysis;
import pl.net.beercrm.model.Customer;
import pl.net.beercrm.model.Product;
import pl.net.beercrm.model.Purchase;
import pl.net.beercrm.service.GenericService;
import pl.net.beercrm.service.PurchaseService;

/**
 * @author Rafi
 * 
 */
@Component
public class DiscountChecker {

	private static final Log log = LogFactory.getLog(DiscountChecker.class);

	@Value("${discount.duration.standard}")
	private String durationStandard;

	@Value("${discount.duration.premium}")
	private String durationPremium;

	@Value("${discount.value.standard}")
	private String valueStandard;

	@Value("${discount.value.premium}")
	private String valuePremium;

	@Value("${discount.delay}")
	private String discountDelay;

	@Value("${discount.threshold.standard}")
	private String thresholdStandard;

	@Value("${discount.threshold.premium}")
	private String thresholdPremium;

	@Autowired
	private GenericService<Analysis, Long> analysisService;

	@Autowired
	private GenericService<Customer, Long> customerService;

	@Autowired
	private PurchaseService<Purchase, Long> purchaseService;

	public Integer checkGlobalDiscount(String customerId) {
		DiscountLevel discountLevel = getDiscountLevel(customerId);
		if (discountLevel == DiscountLevel.STANDARD) {
			return Integer.valueOf(valueStandard);
		} else if (discountLevel == DiscountLevel.PREMIUM) {
			return Integer.valueOf(valuePremium);
		}
		return 0;
	}

	public Date checkDiscountDuration(String customerId) {
		DiscountLevel discountLevel = getDiscountLevel(customerId);
		Calendar calendar = Calendar.getInstance();
		if (discountLevel == DiscountLevel.STANDARD) {
			calendar.add(Calendar.WEEK_OF_YEAR, Integer.valueOf(durationStandard));
			return calendar.getTime();
		} else if (discountLevel == DiscountLevel.PREMIUM) {
			calendar.add(Calendar.WEEK_OF_YEAR, Integer.valueOf(durationPremium));
			return calendar.getTime();
		}
		return new Date();
	}

	private DiscountLevel getDiscountLevel(String customerId) {
		log.debug("Processing discount!");
		DiscountLevel level = DiscountLevel.NONE;

		Date startDate = null;
		Date pauseDate = null;
		Calendar calendar = Calendar.getInstance();
		List<Analysis> analysisList = analysisService.findByGuid(customerId);
		if (analysisList.size() > 0) {
			log.debug("Discount delay check");
			Analysis analysis = analysisList.get(0);
			startDate = analysis.getDiscountStart();
			if (startDate != null) {
				calendar.setTime(startDate);
				calendar.add(Calendar.WEEK_OF_YEAR, Integer.valueOf(discountDelay));
				pauseDate = calendar.getTime();
			}
		}
		
		if (pauseDate == null || (new Date()).after(pauseDate)) {
			List<Customer> persistedCustomers = customerService
					.findByGuid(customerId);
			if (persistedCustomers.size() > 0) {
				log.debug("Prepare discount for customer " + customerId);
				Customer customer = persistedCustomers.get(0);

				// Check birthday discount
				if (customer.getBirthDate() != null) {
					calendar.setTime(customer.getBirthDate());
					int dayOfBirth = calendar.get(Calendar.DAY_OF_MONTH);
					int monthOfBirth = calendar.get(Calendar.MONTH);
					// Compare with actual date
					calendar.setTime(new Date());
					if (dayOfBirth == calendar.get(Calendar.DAY_OF_MONTH)
							&& monthOfBirth == calendar.get(Calendar.MONTH)) {
						log.debug("Birthday discount admitted");
						level = DiscountLevel.STANDARD;
					}
				}

				// Check purchase discount
				int maxPurchase = getMaxPurchase(customerId, startDate);
				if (maxPurchase >= Integer.valueOf(thresholdStandard)
						&& maxPurchase < Integer.valueOf(thresholdPremium)) {
					log.debug("Standard purchase discount admitted");
					level = DiscountLevel.STANDARD;
				} else if (maxPurchase >= Integer.valueOf(thresholdPremium)) {
					log.debug("Premium purchase discount admitted");
					level = DiscountLevel.PREMIUM;
				}
			}
		}
		log.debug("End discount processing! Discount: " + level.toString());
		return level;
	}

	private int getMaxPurchase(String customerId, Date start) {
		Map<String, Integer> map = new HashMap<String, Integer>(0);
		List<Customer> customers = customerService.findByGuid(customerId);
		if (customers.size() > 0) {
			Customer persistedCustomer = customers.get(0);
			List<Purchase> persistedPurchases = purchaseService
					.getPurchaseByCustomer(persistedCustomer);
			for (Purchase purchase : persistedPurchases) {
				// Skip processing purchase which was involved in previous
				// discount
				if (start != null && purchase.getDate().before(start)) {
					continue;
				}
				Product product = purchaseService.getProduct(purchase);
				String key = product.getProductId();
				Integer value = purchase.getAmount();
				if (map.containsKey(key))
					value += map.get(key);
				map.put(key, value);
			}
		}
		return map.isEmpty() ? 0 : Collections.max(map.values());
	}

}
